package yf.mall.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.github.pagehelper.PageHelper;
import com.yf.service.SmsService;
import com.yf.service.WxPayService;
import com.yf.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import yf.mall.common.Const;
import com.yf.response.RRException;
import com.yf.service.impl.BaseServiceImpl;
import yf.mall.dao.*;
import yf.mall.entity.*;
import yf.mall.enums.*;
import yf.mall.service.*;
import yf.mall.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;

/**
 * 商品订单Service实现类
 *
 * @author hxf
 * @email 505860922@qq.com
 * @date Tue Aug 13 14:26:20 CST 2019
 */
@Service
@Slf4j
public class MallOrderServiceImpl extends BaseServiceImpl<MallOrderEntity> implements MallOrderService {

    private MallOrderDao mallOrderDao;

    @Autowired
    private CartService cartService;

    @Autowired
    private MallGoodsDao mallGoodsDao;

    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private UserService userService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private PriceDao priceDao;

    @Autowired
    private LevelDao levelDao;

    @Autowired
    private MallCardDao mallCardDao;

    @Autowired
    private MallStoreService mallStoreService;

    @Autowired
    private MallActService actService;


    @Autowired
    public void setDao(MallOrderDao mallOrderDao) {
        this.mallOrderDao = mallOrderDao;
        super.setBaseDao(mallOrderDao);
    }


    /**
     * 内部方法
     **/

    //创建订单号
    private String createNO(Long userId) {
        return System.currentTimeMillis() + "" + Math.round(Math.random() * 100) + "" + userId;
    }

    //退回物流费
    private void backLogFee(MallOrderEntity entity) {
        //物流费多收
        MallOrderEntity tem = mallOrderDao.get(entity.getId());
        BigDecimal td = tem.getLogFee().subtract(entity.getLogFee());
        if (td.compareTo(BigDecimal.ZERO) > 0) {
            accountService.transfer(Const.ADMIN_ID, getRetailUserId(entity), AccountTypeEnum.CASH.getIndex(), td, "物流费退回:" + tem.getOrderNo());
        }
    }

    //退回物流费
    private void backLogFee(Long orderId, BigDecimal logFee) {
        //物流费多收
        MallOrderEntity tem = mallOrderDao.get(orderId);
        log.info("orderId:" + orderId);
        log.info(tem.getLogFee() + "物流费退回中" + logFee);
        BigDecimal td = tem.getLogFee().subtract(logFee);
        if (td.compareTo(BigDecimal.ZERO) > 0) {
            accountService.transfer(Const.ADMIN_ID, getRetailUserId(tem), AccountTypeEnum.CASH.getIndex(), td, "物流费退回:" + tem.getOrderNo());
        }
    }

    //获取实际当事人
    Long getRetailUserId(MallOrderEntity orderEntity) {
        Long userId = orderEntity.getFromUserId();
        if (userId.equals(Const.ADMIN_ID)) {
            userId = orderEntity.getUserId();
        }
        return userId;
    }

    @Autowired
    private MallGoodsService mallGoodsService;

    /**
     * 外部方法实现 TODO  扣减库存
     **/

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String commitOrder(Long userId, AddressEntity address, String remark, Integer payWay, Integer orderType, String noticeUrl) {
        List<CartEntity> cartEntities = cartService.findByUserIdWithSelected(userId);
        if (cartEntities.isEmpty()) {
            throw new RRException("购物车为空!");
        }
        if (address == null
                || address.getMobile().equals(null)
                || address.getMobile().equals("")
                || address.getMobile().equals("null")
                || address.getDetail().equals("null")
                || address.getDetail().equals("")
                || address.getDetail().equals(null)
                || address.getName().equals("null")
                || address.getName().equals("")
                || address.getName().equals(null)) {
            throw new RRException("请填写收货地址信息");
        }
        //验证是否可以下单
        validateCommitOrder(cartEntities, orderType, userId, remark);
        //创建订单
        MallOrderEntity orderEntity = buildBuyOrder(userId, orderType, address, remark, payWay);
        //生成订单明细 且统计明细的价格 券 物流费
        buildOrderItem(orderEntity, cartEntities);
        //支付之前
        beforePay(orderEntity);
        mallOrderDao.update(orderEntity);
        //代金券的方式直接支付
        if (payWay.equals(MallOrderPayWayEnum.CASH.getIndex())) {
            payByAccount(orderEntity);
            return null;
        } else {//统一下单 TODO 前端如果返回ZERO 代表不需要付钱直接支付成功
            return unionOrder(orderEntity, noticeUrl);
        }

    }


    //即将支付之前 扣掉优惠券 移除提货卡
    void beforePay(MallOrderEntity orderEntity) {
        //清除购物车
        cartService.deleteSelected(orderEntity.getUserId());
        //使用掉提货卡
        actService.useCard(orderEntity);
        //使用掉券
        actService.useTicket(orderEntity);
    }


    /**
     * 创建商城下单订单
     *
     * @param userId
     * @param cartEntities
     */
    private MallOrderEntity buildBuyOrder(Long userId, Integer orderType, AddressEntity address, String remark, Integer payWay) {
        MallOrderEntity orderEntity;
        Integer busType = MallOrderBusTypeEnum.BUY.getIndex();
        BigDecimal price = BigDecimal.ZERO;
        BigDecimal logFee = BigDecimal.ZERO;
        Date payTime = null;
        Integer payStatus = MallOrderPayStatusEnum.NOT_PAID.getIndex();
        Integer quantity = 0;
        Integer orderStatus = MallOrderOrderStatusEnum.NEW.getIndex();
        BigDecimal point = BigDecimal.ZERO;
        BigDecimal coupon = BigDecimal.ZERO;
        BigDecimal voucher = BigDecimal.ZERO;
        if (orderType.equals(MallOrderOrderTypeEnum.TRANSFER.getIndex())) {
            //商城转货订单
            orderEntity = new MallOrderEntity(createNO(userId), Const.ADMIN_ID, orderType, busType, payWay, userId, price, quantity, new Date(), new Date(), orderStatus, payStatus, point, coupon, voucher, remark);
        } else {
            //商城发货订单
            orderEntity = new MallOrderEntity(createNO(userId), Const.ADMIN_ID, orderType, busType, payWay, userId, price, quantity, new Date(), payTime, orderStatus, payStatus, logFee, address.getUserName(), address.getMobile(), address.getProvince(), address.getCity(), address.getCounty(), address.getDetail(), point, coupon, voucher, remark);
            orderEntity.setOrderStatus(MallOrderPayStatusEnum.NOT_PAID.getIndex());
        }
        //生成订单
        mallOrderDao.save(orderEntity);
        return orderEntity;
    }

    /**
     * 创建后台订单
     *
     * @return
     */
    private MallOrderEntity buildSendOrder(Long fromUserId, Long toUserId, Integer orderType, String province, String city, String county, String detail, String userName, String mobile, String remark) {
        MallOrderEntity orderEntity;
        Integer busType = MallOrderBusTypeEnum.SEND.getIndex();
        BigDecimal price = BigDecimal.ZERO;
        Integer quantity = 0;
        Integer orderStatus = MallOrderOrderStatusEnum.NEW.getIndex();
        BigDecimal logFee = BigDecimal.ZERO;
        //生成发货订单
        if (MallOrderOrderTypeEnum.DELIVERY.getIndex() == orderType) {
            orderEntity = new MallOrderEntity(createNO(fromUserId), fromUserId, orderType, busType, toUserId, price, quantity, new Date(), orderStatus, logFee, userName, mobile, province, city, county, detail, remark, MallOrderPayStatusEnum.PAID.getIndex());
        } else { //转货订单
            // 转货是已经完成状态
            orderStatus = MallOrderOrderStatusEnum.DONE.getIndex();
            orderEntity = new MallOrderEntity(createNO(fromUserId), fromUserId, orderType, busType, toUserId, price, quantity, new Date(), orderStatus, remark, MallOrderPayStatusEnum.PAID.getIndex());
        }
        mallOrderDao.save(orderEntity);
        return orderEntity;
    }

    //创建还货订单
    private MallOrderEntity buildReturnOrder(Long userId, String name, String orderNo) {
        Integer busType = MallOrderBusTypeEnum.RETURN.getIndex();
        Integer orderType = MallOrderOrderTypeEnum.TRANSFER.getIndex();
        BigDecimal price = BigDecimal.ZERO;
        Integer quantity = 0;
        Integer orderStatus = MallOrderOrderStatusEnum.DONE.getIndex();
        String remark = name + Const.BUY_ORDER_NO + orderNo;
        MallOrderEntity orderEntity = new MallOrderEntity(createNO(userId), userId, orderType, busType, Const.ADMIN_ID, price, quantity, new Date(), orderStatus, remark, MallOrderPayStatusEnum.PAID.getIndex());
        mallOrderDao.save(orderEntity);
        return orderEntity;
    }

    //创建自动购买订单
    private MallOrderEntity buildAutoBuyOrder(Long userId, String name, String orderNo) {
        Integer busType = MallOrderBusTypeEnum.AUTO_BUY.getIndex();
        Integer orderType = MallOrderOrderTypeEnum.TRANSFER.getIndex();
        BigDecimal price = BigDecimal.ZERO;
        Integer quantity = 0;
        Integer orderStatus = MallOrderOrderStatusEnum.DONE.getIndex();
        String remark = name + Const.BUY_ORDER_NO + orderNo;
        Integer payWay = MallOrderPayWayEnum.CASH.getIndex();
        Integer payStatus = MallOrderPayStatusEnum.PAID.getIndex();
        BigDecimal point = BigDecimal.ZERO;
        BigDecimal coupon = BigDecimal.ZERO;
        BigDecimal voucher = BigDecimal.ZERO;
        MallOrderEntity orderEntity = new MallOrderEntity(createNO(userId), Const.ADMIN_ID, orderType, busType, payWay, userId, price, quantity, new Date(), new Date(), orderStatus, payStatus, point, coupon, voucher, remark);
        mallOrderDao.save(orderEntity);
        return orderEntity;
    }

    /**
     * 从购物车构建订单明细
     *
     * @param orderEntity
     * @param cartEntities
     */
    private void buildOrderItem(MallOrderEntity orderEntity, List<? extends ItemVo> itemVos) {
        //总价格
        BigDecimal totalPrice = new BigDecimal(0);
        //总积分
        BigDecimal totalPoint = new BigDecimal(0);
        //总优惠券
        BigDecimal totalCoupon = new BigDecimal(0);
        //总购物券
        BigDecimal totalVocher = new BigDecimal(0);
        //总物流费
        BigDecimal totalLogFee = new BigDecimal(0);
        //总数量
        Integer totalQuantity = 0;
        //生成订单明细
        for (ItemVo itemVo : itemVos) {
            MallGoodsEntity mallGoodsEntity = mallGoodsDao.get(itemVo.getGoodsId());
            TicketVo ticketVo = actService.getTicketVo(mallGoodsEntity.getId());
            OrderItemEntity orderItemEntity = new OrderItemEntity(orderEntity.getId(), itemVo.getGoodsId(), itemVo.getSkuName(), mallGoodsEntity.getName(), mallGoodsEntity.getNowPrice(), mallGoodsEntity.getWeight(), mallGoodsEntity.getImg(),
                    itemVo.getQuantity(),
                    ticketVo.getPoint(),
                    ticketVo.getCoupon()
                    , ticketVo.getVoucher());
            //计算代理产品价格
            calculatePrice(orderEntity.getFromUserId(), orderEntity.getUserId(), orderItemEntity);
            orderItemDao.save(orderItemEntity);
            //统计总金额
            totalPrice = totalPrice.add(orderItemEntity.getTotalPrice());
            //累计总积分
            totalPoint = totalPoint.add(orderItemEntity.getTotalPoint());
            //累计总优惠券
            totalCoupon = totalCoupon.add(orderItemEntity.getTotalCoupon());
            //累计总购物券
            totalVocher = totalVocher.add(orderItemEntity.getTotalVoucher());
            //发货计算物流费
            if (orderEntity.getOrderType().equals(MallOrderOrderTypeEnum.DELIVERY.getIndex())) {
                BigDecimal logFee = computeLogFee(mallGoodsEntity, itemVo.getQuantity(), orderEntity.getProvince());
                totalLogFee = totalLogFee.add(logFee);
            }
            //累计总数量
            totalQuantity += orderItemEntity.getQuantity();
        }
        //更新订单 的总金额与可使用的优惠券
        orderEntity.setPrice(totalPrice);
        orderEntity.setPoint(totalPoint);
        orderEntity.setCoupon(totalCoupon);
        orderEntity.setVoucher(totalVocher);
        orderEntity.setQuantity(totalQuantity);
        orderEntity.setLogFee(totalLogFee);
        mallOrderDao.update(orderEntity);
    }

    //获取订单实际要支付的金额 加上物流费 减去所有抵扣券
    public BigDecimal getRetailPrice(MallOrderEntity orderEntity) {
        //如果需要物流费 加上物流费
        BigDecimal tem = orderEntity.getPrice();
        //如果优惠券可以抵扣
        if (orderEntity.getCoupon() != null && orderEntity.getCoupon().compareTo(BigDecimal.ZERO) > 0) {
            //优惠券抵扣价格
            tem = tem.subtract(orderEntity.getCoupon());
        }
        //购物券可以抵扣
        if (orderEntity.getVoucher() != null && orderEntity.getVoucher().compareTo(BigDecimal.ZERO) > 0) {
            //优惠券抵扣价格
            tem = tem.subtract(orderEntity.getVoucher());
        }
        //提货卡可以抵扣
        BigDecimal cardPrice = actService.getCardPrice(orderEntity);
        if (cardPrice.compareTo(BigDecimal.ZERO) > 0) {
            tem = tem.subtract(cardPrice);
        }
        //收取邮费
        if (orderEntity.getLogFee() != null) {
            tem = tem.add(orderEntity.getLogFee());
        }
        if (tem.compareTo(BigDecimal.ZERO) < 0) {
            tem = BigDecimal.ZERO;
        }
        return tem;

    }

    //通知入库
    void noticeOrder(MallOrderEntity orderEntity) {
        List<OrderItemEntity> itemEntities = orderItemDao.findByOrderId(orderEntity.getId());
        StringBuffer sb = new StringBuffer();
        itemEntities.forEach(orderItemEntity -> {
            sb.append(orderItemEntity.getName() + "X" + orderItemEntity.getQuantity());
        });
        UserEntity user = userDao.get(orderEntity.getUserId());
        UserEntity fromUser = userDao.get(orderEntity.getFromUserId());
        UserEntity topUser = userDao.get(user.getPid());
        //转货 发送入库通知给本人 发送出库通知给转出人
        if (orderEntity.getOrderType().equals(MallOrderOrderTypeEnum.TRANSFER.getIndex())) {
            noticeService.sendOrderIn(user.getOpenId(), user.getName(), sb.toString());
            noticeService.sendOrderOut(fromUser.getOpenId(), orderEntity.getOrderNo(), sb.toString());
        }

        //商城下单 通知上级与推荐人
        if (topUser != null && orderEntity.getBusType().equals(MallOrderBusTypeEnum.BUY.getIndex())) {
            noticeService.sendOrderDone(topUser.getOpenId(), user.getName(), sb.toString(), MallOrderPayWayEnum.indexOf(orderEntity.getPayWay()), orderEntity.getPrice());
            //推荐人另有其人
            if (!user.getRid().equals(user.getPid())) {
                UserEntity referUser = userDao.get(user.getRid());
                noticeService.sendOrderDone(referUser.getOpenId(), user.getName(), sb.toString(), MallOrderPayWayEnum.indexOf(orderEntity.getPayWay()), orderEntity.getPrice());
            }
        }
    }

    @Autowired
    private NoticeService noticeService;


    @Autowired
    private WxPayService wxPayService;


    //统一下单
    @Override
    public String unionOrder(MallOrderEntity mallOrderEntity, String noticeUrl) {
        if (mallOrderEntity.getPayStatus().equals(MallOrderPayStatusEnum.PAID.getIndex())) {
            throw new RRException("请勿提交已支付的订单!");
        }
        BigDecimal decimal = getRetailPrice(mallOrderEntity);
        //如果不用付钱
        if (decimal.compareTo(BigDecimal.ZERO) == 0) {
            afterPayOrder(mallOrderEntity);
            return "ZERO";
        }
        UserEntity userEntity = userDao.get(mallOrderEntity.getUserId());
        return wxPayService.createWebConfig(mallOrderEntity.getOrderNo(), decimal.doubleValue(), "购买产品", userEntity.getOpenId(), noticeUrl);
    }

    /**
     * 商城下单的单走此验证
     * 是否禁止转货 是否可以发货
     * 商城购买的 下架产品不能购买
     * 活动未开始不能下单  积分不够不能下单  提货卡活动、限购级别、限购数量、限购捆绑销售
     *
     * @param orderEntity
     */
    private void validateCommitOrder(List<? extends ItemVo> itemVos, Integer orderType, Long userId, String remark) {
        for (ItemVo itemVo : itemVos) {
            MallGoodsEntity goodsEntity = mallGoodsDao.get(itemVo.getGoodsId());
            if (MallGoodsShelfEnum.ON.getIndex() != goodsEntity.getShelf()) {
                throw new RRException(goodsEntity.getName() + "已经下架!");
            }
            //存在活动查看活动存在的一些限制
            actService.validateCommit(userId, remark, itemVo, itemVos, orderType);
        }
    }

    /**
     * 验证后台转货发货
     */
    private void validateSendOrder(List<? extends ItemVo> itemVos, Long fromUserId, Long toUserId, Integer orderType) {
        for (ItemVo itemVo : itemVos) {
            actService.validateSend(itemVo, orderType, fromUserId, toUserId);
        }
    }


    @Autowired
    private MallActDao mallActDao;


    @Override
    public void payment(String orderNo) {
        MallOrderEntity orderEntity = mallOrderDao.findByOrderNo(orderNo);
        if (orderEntity == null) {
            throw new RRException("订单不存在!");
        }
        UserEntity userEntity = userDao.get(orderEntity.getUserId());
        //上级
        UserEntity topUser = userDao.get(userEntity.getPid());
        List<OrderItemEntity> orderItemEntities = orderItemDao.findByOrderId(orderEntity.getId());
        //需要进货的
        List<OrderItemEntity> needBuyItems = new ArrayList<>();
        //需要还货的
        List<OrderItemEntity> needBackItems = new ArrayList<>();
        for (OrderItemEntity item : orderItemEntities) {
            //非代理产品跳过
            MallGoodsEntity goodsEntity = mallGoodsDao.get(item.getGoodsId());
            if (!goodsEntity.getSaleType().equals(MallGoodsSaleTypeEnum.AGENT.getIndex())) {
                continue;
            }
            //判断价格
            PriceEntity topUserPrice = priceDao.findByUserIdAndGoodsId(topUser.getId(), item.getGoodsId());
            PriceEntity userPrice = priceDao.findByUserIdAndGoodsId(userEntity.getId(), item.getGoodsId());
            BigDecimal tem = userPrice.getPrice().subtract(topUserPrice.getPrice()).multiply(new BigDecimal(item.getQuantity()));
            //无收款的产品 我的进货价不于购买人的价格
            if (tem.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            OrderItemEntity orderItemEntity = new OrderItemEntity(orderEntity.getId(), item.getGoodsId(), null, item.getName(), userPrice.getPrice(), item.getWeight(), item.getImg(), null, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
            //判断库存是否充足
            MallStoreEntity storeEntity = mallStoreDao.findByUserIdAndGoodsId(topUser.getId(), item.getGoodsId());
            //库存充足  还货
            if (storeEntity != null && storeEntity.getQuantity() >= item.getQuantity()) {
                orderItemEntity.setQuantity(item.getQuantity());
                //加入还货
                needBackItems.add(orderItemEntity);
                continue;
            }
            //库存不足 足的地方还了  不足的地方补
            Integer temQ = item.getQuantity();
            if (storeEntity != null && storeEntity.getQuantity() > 0) {
                temQ = item.getQuantity() - storeEntity.getQuantity();
                //需要补的
                OrderItemEntity temItem = new OrderItemEntity(orderEntity.getId(), item.getGoodsId(), null, item.getName(), userPrice.getPrice(), item.getWeight(), item.getImg(), storeEntity.getQuantity(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
                needBackItems.add(temItem);
            }
            //需要买的
            orderItemEntity.setQuantity(temQ);
            needBuyItems.add(orderItemEntity);
        }
        //还货
        if (needBackItems.size() > 0) {
            autoBack(topUser.getId(), needBackItems, userEntity.getName(), orderNo);
        }
        //补货
        if (needBuyItems.size() > 0) {
            autoBuy(topUser.getId(), needBuyItems, userEntity.getName(), orderNo);
        }

    }

    /**
     * 库存够的时候 直接把货还给公司即可 拿全款
     *
     * @param userId
     * @param items
     */
    void autoBack(Long userId, List<OrderItemEntity> items, String name, String orderNo) {
        //生成订单
        MallOrderEntity orderEntity = buildReturnOrder(userId, name, orderNo);
        //生成明细
        buildOrderItem(orderEntity, items);
        //转货
        mallStoreService.transfer(orderEntity.getId());
    }

    //自动购买业务 但是库存不给
    void autoBuy(Long userId, List<OrderItemEntity> items, String name, String orderNo) {
        //生成订单
        MallOrderEntity orderEntity = buildAutoBuyOrder(userId, name, orderNo);
        //生成明细
        buildOrderItem(orderEntity, items);
        //扣钱
        accountService.autoPay(userId, AccountTypeEnum.CASH.getIndex(), orderEntity.getPrice(), orderEntity.getOrderNo());
        //生成代收款
        codOrder(orderEntity);
        //送经验值
        accountService.rewardExp(userId, orderEntity.getPrice(), name, orderNo, true);
    }

    @Autowired
    private MallStoreDao mallStoreDao;


    /**
     * 对进货订单进行代收款业务
     *
     * @param mallOrderEntity
     */
    void codOrder(MallOrderEntity mallOrderEntity) {
        UserEntity userEntity = userDao.get(mallOrderEntity.getUserId());
        //公司不处理
        if (userEntity.getPid().equals(Const.ADMIN_ID)) {
            return;
        }
        //级别高的上级
        UserEntity topUser = userService.getLvTopUser(userEntity.getId());
        //级别判断
        LevelEntity topUserLevel = levelDao.get(topUser.getLevelId());
        LevelEntity userLevel = levelDao.get(userEntity.getLevelId());
        //购买者级别要小于上级级别
        if (userLevel.getLv() < topUserLevel.getLv()) {
            return;
        }
        //开始计算价格
        BigDecimal total = BigDecimal.ZERO;
        List<OrderItemEntity> items = orderItemDao.findByOrderId(mallOrderEntity.getId());
        for (OrderItemEntity item : items) {
            MallGoodsEntity mallGoods = mallGoodsDao.get(item.getGoodsId());
            //零售产品跳过
            if (!mallGoods.getSaleType().equals(MallGoodsSaleTypeEnum.AGENT.getIndex())) {
                continue;
            }
            PriceEntity topUserPrice = priceDao.findByUserIdAndGoodsId(topUser.getId(), item.getGoodsId());
            PriceEntity userPrice = priceDao.findByUserIdAndGoodsId(userEntity.getId(), item.getGoodsId());
            BigDecimal tem = userPrice.getPrice().subtract(topUserPrice.getPrice()).multiply(new BigDecimal(item.getQuantity()));
            //有差价再显示
            if (tem.compareTo(BigDecimal.ZERO) > 0) {
                total = total.add(userPrice.getPrice().multiply(new BigDecimal(item.getQuantity())));
            }
        }
        //没有差价返回
        if (total.compareTo(BigDecimal.ZERO) < 1) {
            return;
        }
        //生成代收款
        AccountRecordEntity record = new AccountRecordEntity(Const.ADMIN_ID, topUser.getId(), AccountTypeEnum.CASH.getIndex(), total, null, null, new Date(), mallOrderEntity.getOrderNo(), AccountRecordStatusEnum.WAIT.getIndex(), AccountRecordBusEnum.PAYMENT.getIndex());
        accountRecordDao.save(record);
    }


    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountRecordDao accountRecordDao;

    //账户支付
    void payByAccount(MallOrderEntity orderEntity) {
        if (orderEntity.getPayStatus().equals(MallOrderPayStatusEnum.PAID.getIndex())) {
            throw new RRException("已支付,请勿重复支付!");
        }
        //获取实际要支付的费用
        BigDecimal tem = getRetailPrice(orderEntity);
        if (tem.compareTo(BigDecimal.ZERO) > 0) {
            //给公司转账
            accountService.pay(orderEntity.getUserId(), AccountTypeEnum.CASH.getIndex(), tem, orderEntity.getOrderNo());
        }
        afterPayOrder(orderEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payByWx(String orderNo) {
        MallOrderEntity orderEntity = mallOrderDao.findByOrderNo(orderNo);
        if (orderEntity == null) {
            log.error("订单不存在!");
        }
        //已经支付
        if (orderEntity.getPayStatus().equals(MallOrderPayStatusEnum.PAID.getIndex())) {
            return;
        }
        afterPayOrder(orderEntity);
    }

    //商城进货支付完成后
    public void afterPayOrder(MallOrderEntity orderEntity) {
        mallStoreService.transfer(orderEntity.getId());
        //转货就已经完成了
        if (orderEntity.getOrderType().equals(MallOrderOrderTypeEnum.TRANSFER.getIndex())) {
            orderEntity.setOrderStatus(MallOrderOrderStatusEnum.DONE.getIndex());
        }
        //设置支付状态
        orderEntity.setPayStatus(MallOrderPayStatusEnum.PAID.getIndex());
        orderEntity.setPayTime(new Date());
        mallOrderDao.update(orderEntity);
        //代收款
        codOrder(orderEntity);
        //活动逻辑
        actService.fire(orderEntity);
        //通知
        noticeOrder(orderEntity);
        //TODO 捐赠通知
//        noticeWelFare(orderEntity);
    }
    //公益基金通知
    void noticeWelFare(MallOrderEntity mallOrderEntity) {
        UserEntity userEntity = userDao.get(mallOrderEntity.getUserId());
        //通知
        noticeService.noticeWelFare(userEntity.getOpenId(), userEntity.getName(), new BigDecimal(mallOrderEntity.getQuantity() * 0.1));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MallOrderEntity adminPay(Long orderId) {
        MallOrderEntity mallOrderEntity = get(orderId);
        if (mallOrderEntity.getOrderStatus().equals(MallOrderPayStatusEnum.PAID.getIndex())) {
            throw new RRException("请勿重复支付!");
        }
        afterPayOrder(mallOrderEntity);
        return mallOrderEntity;
    }

    //计算代理产品价格
    void calculatePrice(Long fromUserId, Long userId, OrderItemEntity itemEntity) {
        MallGoodsEntity mallGoodsEntity = mallGoodsDao.get(itemEntity.getGoodsId());
        //零售产品跳过
        if (!mallGoodsEntity.getSaleType().equals(MallGoodsSaleTypeEnum.AGENT.getIndex())) {
            return;
        }
        //获取公司外  价格最低的价格
        PriceEntity priceEntity;
        PriceEntity fromUserPrice = priceDao.findByUserIdAndGoodsId(fromUserId, itemEntity.getGoodsId());
        PriceEntity toUserPrice = priceDao.findByUserIdAndGoodsId(userId, itemEntity.getGoodsId());
        if (fromUserId.equals(Const.ADMIN_ID)) {
            //计算级别
            priceEntity = toUserPrice;
        } else if (userId.equals(Const.ADMIN_ID)) {
            //计算级别
            priceEntity = fromUserPrice;
        } else {
            //选取高价
            if (fromUserPrice.getPrice().compareTo(toUserPrice.getPrice()) > 0) {
                priceEntity = fromUserPrice;
            } else {
                priceEntity = toUserPrice;
            }
        }
        itemEntity.setPrice(priceEntity.getPrice());
    }

    @Autowired
    private LogRuleService logRuleService;

    //计算订单明细所有产品物流费总数 TODO 根据sku的重量收取邮费
    @Override
    public BigDecimal computeLogFee(List<? extends ItemVo> items, String province) {
        BigDecimal logFee = BigDecimal.ZERO;
        for (ItemVo item : items) {
            MallGoodsEntity goodsEntity = mallGoodsDao.get(item.getGoodsId());
            logFee = logFee.add(computeLogFee(goodsEntity, item.getQuantity(), province));
        }
        return logFee;
    }


    //计算单个产品的物流费
    BigDecimal computeLogFee(MallGoodsEntity goodsEntity, Integer quantity, String province) {
        //包邮产品 或者  没有设置邮费
        if (goodsEntity.getLogType() == null || goodsEntity.getLogType().equals(MallGoodsLogTypeEnum.FREE.getIndex())) {
            return BigDecimal.ZERO;
        }
        //满免
        if (goodsEntity.getLogType().equals(MallGoodsLogTypeEnum.FULL.getIndex())) {
            //数量不够免物流费
            if (goodsEntity.getFullNumber() > quantity) {
                return goodsEntity.getLogFee().multiply(new BigDecimal(quantity));
            }
        }
        //计重
        if (goodsEntity.getLogType().equals(MallGoodsLogTypeEnum.WEIGHT.getIndex())) {
            BigDecimal result = BigDecimal.ZERO;
            //每箱子重新计算一次
            while (quantity > 0) {
                Integer tem = quantity > goodsEntity.getPerBox() ? goodsEntity.getPerBox() : quantity;
                result = result.add(logRuleService.computeLogFee(province, goodsEntity.getWeight().multiply(new BigDecimal(tem))));
                quantity = quantity - goodsEntity.getPerBox().intValue();
            }
            return result;
        }
        return BigDecimal.ZERO;
    }


//    @Override
//    public Long commitOrder(Long userId, Long goodsId, String skuName, Integer quantity, AddressEntity address) {
//        //生成订单
//        MallOrderEntity orderEntity = new MallOrderEntity(createNO(userId), userId, new Date(), MallOrderPayStatusEnum.NOT_PAID.getIndex(), address.getName(), address.getMobile(), address.getAddress(), MallOrderOrderStatusEnum.NEW.getIndex());
//        mallOrderDao.save(orderEntity);
//        MallGoodsEntity mallGoodsEntity = mallGoodsDao.get(goodsId);
//        //生成明细
//        OrderItemEntity orderItemEntity = new OrderItemEntity(orderEntity.getId(), goodsId, skuName, mallGoodsEntity.getName(), mallGoodsEntity.getNowPrice(), mallGoodsEntity.getWeight(), mallGoodsEntity.getImg(), quantity);
//        orderItemDao.save(orderItemEntity);
//        //更新总数
//        orderEntity.setQuantity(1);
//        orderEntity.setPrice(mallGoodsEntity.getNowPrice());
//        return orderEntity.getId();
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<MallOrderVo> listOrder(Long userId, int page, int limit) {
        PageHelper.startPage(page, limit).setOrderBy("mallOrder.id desc");

        List<MallOrderVo> orderVos = mallOrderDao.findByUserId(userId);
        //组装明细
        for (MallOrderVo orderVo : orderVos) {
            List<OrderItemEntity> itemEntities = orderItemDao.findByOrderId(orderVo.getMallOrder().getId());
            orderVo.getMallOrder().setItems(itemEntities);
        }
        return orderVos;
    }

    /**
     * Long
     * 根据用户id以及订单状态去查询订单明细
     *
     * @param userId
     * @param status
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<MallOrderVo> findByUserIdAndStatus(Long userId, int status) {

        List<MallOrderVo> orderVos = mallOrderDao.queryByUserIdAndStatus(userId, status);
        //组装明细
        for (MallOrderVo orderVo : orderVos) {
            List<OrderItemEntity> itemEntities = orderItemDao.findByOrderId(orderVo.getMallOrder().getId());
            orderVo.getMallOrder().setItems(itemEntities);
        }
        return orderVos;
    }

    @Override
    public List<MallOrderEntity> findReturn(String orderNo) {
        return mallOrderDao.findByRemarkAndBusType(orderNo, MallOrderBusTypeEnum.RETURN.getIndex());
    }


    @Override
    public List<MallOrderEntity> findAutoBuy(String orderNo) {
        return mallOrderDao.findByRemarkAndBusType(orderNo, MallOrderBusTypeEnum.AUTO_BUY.getIndex());
    }

    @Override
    public MallOrderEntity buildBackOrder(MallOrderEntity orderEntity) {
        orderEntity.setId(null);
        orderEntity.setFromUserId(orderEntity.getUserId());
        orderEntity.setUserId(orderEntity.getFromUserId());
        orderEntity.setBusType(MallOrderBusTypeEnum.BACK.getIndex());
        orderEntity.setOrderNo(createNO(orderEntity.getUserId()));
        orderEntity.setRemark(orderEntity.getRemark().replace(Const.BUY_ORDER_NO, Const.BACK_ORDER_NO));
        return orderEntity;
    }

    /*****后台部分*****/


    @Override
    public List<MallOrderVo> queryListVo(MallOrderVo mallOrderVo) {
        return mallOrderDao.queryListVo(mallOrderVo);
    }

    @Override
    public MallOrderVo getVo(Long id) {
        return mallOrderDao.getVo(id);
    }

    @Override
    public MallOrderVo getVo(String orderNo) {
        return mallOrderDao.getVoByOrderNo(orderNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(MallOrderVo mallOrderVo) {
        List<OrderItemEntity> itemEntities = mallOrderVo.getMallOrder().getItems();
        UserEntity fromUser = mallOrderVo.getFromUser();
        UserEntity toUser = mallOrderVo.getUser();
        //验证账户
        userService.validateUser(fromUser, toUser);
        fromUser = userDao.findByCode(fromUser.getCode());
        toUser = userDao.findByCode(toUser.getCode());
        String remark = mallOrderVo.getMallOrder().getRemark();
        Integer orderType = mallOrderVo.getMallOrder().getOrderType();
        if (orderType == null) {
            orderType = MallOrderOrderTypeEnum.TRANSFER.getIndex();
        }
        //验证明细
        validateSendOrder(itemEntities, fromUser.getId(), toUser.getId(), orderType);
        //生成订单
        MallOrderEntity mallOrderEntity = buildSendOrder(fromUser.getId(), toUser.getId(), orderType, mallOrderVo.getMallOrder().getProvince(), mallOrderVo.getMallOrder().getCity(), mallOrderVo.getMallOrder().getCounty(), mallOrderVo.getMallOrder().getDetail(), mallOrderVo.getMallOrder().getUserName(), mallOrderVo.getMallOrder().getMobile(), remark);
        //生成明细
        buildOrderItem(mallOrderEntity, itemEntities);
        //实体化
        mallOrderDao.update(mallOrderEntity);
        //转货操作
        mallStoreService.transfer(mallOrderEntity.getId());
        //支付物流费 谁发货扣谁的
        accountService.pay(mallOrderEntity.getFromUserId(), AccountTypeEnum.CASH.getIndex(), mallOrderEntity.getLogFee(), mallOrderEntity.getOrderNo());
        //转货返经验值
        transferChangeExp(mallOrderEntity, true);
        //通知
        noticeOrder(mallOrderEntity);

    }


    /**
     * 转货业务改变经验值
     *
     * @param orderEntity
     */
    void transferChangeExp(MallOrderEntity orderEntity, boolean reward) {
        LevelEntity fl = levelDao.findByUserId(orderEntity.getFromUserId());
        LevelEntity tl = levelDao.findByUserId(orderEntity.getUserId());
        //公司或者高级别转给你的
        if (orderEntity.getFromUserId().equals(Const.ADMIN_ID) || fl.compareTo(tl) > 0) {
            UserEntity userEntity = userDao.get(orderEntity.getUserId());
            accountService.rewardExp(orderEntity.getUserId(), orderEntity.getPrice(), orderEntity.getOrderNo(), userEntity.getName(), reward);
        }
        //转给比自己级别低的 或者转给公司
        if (orderEntity.getUserId().equals(Const.ADMIN_ID) || fl.compareTo(tl) < 0) {
            UserEntity userEntity = userDao.get(orderEntity.getFromUserId());
            accountService.backExp(orderEntity.getFromUserId(), orderEntity.getPrice(), orderEntity.getOrderNo(), userEntity.getName());
        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void downLoad(HttpServletResponse response) {
        List<Long> ids = new ArrayList<>();
        List<OrderDownVo> datas = new ArrayList<>();
        List<MallOrderEntity> mallOrderEntities = mallOrderDao.findNotDelivered();
        Map<String, Integer> dataSum = new HashMap<>();
        mallOrderEntities.forEach(mallOrderEntity -> {
            OrderDownVo orderDownVo = new OrderDownVo();
            orderDownVo.setId(mallOrderEntity.getId());
            orderDownVo.setUserName(mallOrderEntity.getUserName());
            orderDownVo.setRemark(mallOrderEntity.getRemark());
            //编码
            UserEntity user = userDao.get(mallOrderEntity.getUserId());
            orderDownVo.setMobile(mallOrderEntity.getMobile() + " " + user.getCode());
            orderDownVo.setAddress(mallOrderEntity.getAddress());
            orderDownVo.setOrderNo(mallOrderEntity.getOrderNo());
            orderDownVo.setLogFee(mallOrderEntity.getLogFee());
            StringBuffer sb = new StringBuffer();
            List<OrderItemEntity> itemEntities = orderItemDao.findByOrderId(mallOrderEntity.getId());
            itemEntities.forEach(orderItemEntity -> {
                String skuName = orderItemEntity.getSkuName();
                MallGoodsEntity mallGoodsEntity = mallGoodsDao.get(orderItemEntity.getGoodsId());
                if (skuName == null) skuName = "";
                String str = orderItemEntity.getName() + skuName + "X" + orderItemEntity.getQuantity() + "(" + mallGoodsEntity.getUnit() + ")  ";
                sb.append(str);
                //统计总数
                String key = orderItemEntity.getName() + skuName + " " + mallGoodsEntity.getUnit();
                Integer quantity = 0;
                if (dataSum.containsKey(key)) {
                    quantity = dataSum.get(key);
                }
                quantity += orderItemEntity.getQuantity();
                dataSum.put(key, quantity);
            });
            orderDownVo.setDetail(sb.toString());
            datas.add(orderDownVo);
            ids.add(mallOrderEntity.getId());
        });
        //更新
        if (ids.size() > 0) {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
            try {
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
                WriteSheet writeSheet1 = EasyExcel.writerSheet(0, "订单").head(OrderDownVo.class).build();
                excelWriter.write(datas, writeSheet1);
//                EasyExcel.write(response.getOutputStream(), OrderDownVo.class).sheet(0,"订单").doWrite(datas);
                //汇总
                List<OrderSumVo> orderSumVos = new ArrayList<>();
                dataSum.keySet().forEach(key -> {
                    OrderSumVo orderSumVo = new OrderSumVo(key, dataSum.get(key));
                    orderSumVos.add(orderSumVo);
                });
                WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "汇总").head(OrderSumVo.class).build();
                excelWriter.write(orderSumVos, writeSheet2);
                excelWriter.finish();
//                EasyExcel.write(response.getOutputStream(), OrderSumVo.class).sheet(1,"汇总").doWrite(orderSumVos);
                mallOrderDao.updateDelivering(ids);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    //ID 单号 物流公司 物流费
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upload(InputStream inputStream) {
        EasyExcel.read(inputStream, OrderUpVo.class, new UploadDataListener()).sheet().doRead();
    }

    class UploadDataListener extends AnalysisEventListener<OrderUpVo> {


        @Override
        @Transactional(rollbackFor = Exception.class)
        public void invoke(OrderUpVo orderUpVo, AnalysisContext analysisContext) {
            MallOrderEntity mallOrderEntity = mallOrderDao.get(orderUpVo.getId());
            if (mallOrderEntity == null) {
                log.info(orderUpVo.getId() + "");
            }
            mallOrderEntity.setLogCompany(orderUpVo.getLogCompany());
            mallOrderEntity.setLogNo(orderUpVo.getLogNo());
            mallOrderEntity.setOrderStatus(MallOrderOrderStatusEnum.DELIVERED.getIndex());
            //退物流费
            backLogFee(orderUpVo.getId(), orderUpVo.getLogFee());
            mallOrderEntity.setLogFee(orderUpVo.getLogFee());
            mallOrderDao.update(mallOrderEntity);
            //通知发货
            UserEntity userEntity = userDao.get(mallOrderEntity.getUserId());
            noticeService.sendOrderLog(userEntity.getOpenId(), mallOrderEntity.getOrderNo(), userEntity.getName(), mallOrderEntity.getLogCompany(), mallOrderEntity.getLogNo(), mallOrderEntity.getAddress());
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    // 商城未支付状态 退券   商城已支付的未发货   后台未发货
    public MallOrderEntity deleteOrder(Long userId, Long orderId) {
        MallOrderEntity mallOrderEntity = get(orderId);
        //然后再执行 否则有并发问题
        if (!mallOrderEntity.getCancel()) {
            throw new RRException("订单属于不可取消状态!");
        }
        //更新为已取消状态
        mallOrderEntity.setOrderStatus(MallOrderOrderStatusEnum.CANCELED.getIndex());
        mallOrderDao.update(mallOrderEntity);

        // 不是自己的订单
        if (mallOrderEntity == null || !userId.equals(Const.ADMIN_ID) && !mallOrderEntity.getUserId().equals(userId)) {
            throw new RRException("只能取消自己的订单!");
        }

        //支付的 超过退货期
        if (mallOrderEntity.getPayStatus().equals(MallOrderPayStatusEnum.PAID.getIndex()) && DateUtil.getDays(mallOrderEntity.getOrderTime(), new Date()) >= Const.BACK_DAY) {
            throw new RRException("已超过取消时间,请联系客服处理!");
        }

        //不管取消什么类型的订单 未支付的退券 已经支付的退券与钱
        accountService.cancel(mallOrderEntity.getOrderNo());
        //分场景处理

        Integer orderType = mallOrderEntity.getOrderType();
        Integer busType = mallOrderEntity.getBusType();
        Integer payStatus = mallOrderEntity.getPayStatus();
        //暂时 商城(未支付发货,未支付转货,已支付发货) 后台(发货订单)
        //商城 退钱
        if (MallOrderBusTypeEnum.BUY.getIndex() == busType) {
            //钱与券上面已经退了 触发取消活动
            actService.cancel(mallOrderEntity);
            //未支付的上面已经退券 如下判断已支付发货  已支付的转货是完成状态无法退货无需操作 已经支付的退货(退货款部分)
            if (payStatus.equals(MallOrderPayStatusEnum.PAID.getIndex())) {
                //商城的 退货 已经退券了 不用退货到库存 只要退给代理 补货的订单
                mallStoreService.backCod(mallOrderEntity.getOrderNo());
                //追回自动购买的情况
                mallStoreService.backAutoBuy(mallOrderEntity.getOrderNo());
                //发货订单退回到仓库
                if (orderType.equals(MallOrderOrderTypeEnum.DELIVERY.getIndex())) {
                    //退回到代理仓库
                    mallStoreService.backDelivery(mallOrderEntity.getOrderNo());
                }
            }
        }
        //后台发货
        if (MallOrderBusTypeEnum.SEND.getIndex() == busType && orderType.equals(MallOrderOrderTypeEnum.DELIVERY.getIndex())) {
            //退回到代理仓库
            mallStoreService.backDelivery(mallOrderEntity.getOrderNo());
        }


        return mallOrderEntity;

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(MallOrderEntity entity) {
        backLogFee(entity);
        super.update(entity);
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void renew() {
        mallOrderDao.renew();
    }


    @Override
    public void downLoad(HttpServletResponse response, String code, String startDate, String endDate) {
        UserEntity userEntity = userDao.findByCode(code);
        List<MallOrderEntity> mallOrderEntities = mallOrderDao.findUserPaid(userEntity.getId(), DateUtil.getStartTime(startDate), DateUtil.getEndTime(endDate));
        List<OrderSumVo> orderSumVos = sumOrder(mallOrderEntities);
        try {
            // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("结算汇总", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), OrderSumVo.class).sheet("模板").doWrite(orderSumVos);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public List<OrderSumVo> sumOrder(List<MallOrderEntity> orderEntities) {
        List<OrderSumVo> orderSumVos = new ArrayList<>();
        Map<String, Integer> orderSum = new HashMap<>();
        orderEntities.forEach(mallOrderEntity -> {
            List<OrderItemEntity> orderItemEntities = orderItemDao.findByOrderId(mallOrderEntity.getId());
            orderItemEntities.forEach(orderItemEntity -> {
                Integer quantity = 0;
                String key = orderItemEntity.getName();
                if (orderSum.containsKey(key)) {
                    quantity = orderSum.get(key);
                }
                quantity += orderItemEntity.getQuantity();
                orderSum.put(key, quantity);
            });
        });
        orderSum.keySet().forEach(key -> {
            OrderSumVo orderSumVo = new OrderSumVo(key, orderSum.get(key));
            orderSumVos.add(orderSumVo);
        });
        return orderSumVos;
    }

    @Override
    public MallOrderEntity findByOrderNo(String orderNo) {
        return mallOrderDao.findByOrderNo(orderNo);
    }

    /**
     * Long
     * 确定收货
     *
     * @param userID
     * @param orderNo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MallOrderEntity sureReceipt(Long userID, String orderNo) {
        MallOrderEntity orderEntity = this.mallOrderDao.findByOrderNo(orderNo);
//        判断订单是否发货了以及是不是它的订单
        if (!userID.equals(orderEntity.getUserId())) {
            throw new RRException("不是他的订单不能确定收货");
        }
        if (MallOrderOrderStatusEnum.DELIVERED.getIndex() != (orderEntity.getOrderStatus()) && orderEntity.getOrderStatus().equals(MallOrderOrderStatusEnum.RECEIVED.getIndex())) {
            throw new RRException("该订单不能确认收货");
        }

        // 确定收货
        orderEntity.setOrderStatus(MallOrderOrderStatusEnum.RECEIVED.getIndex());

        this.mallOrderDao.update(orderEntity);
        this.accountService.doneTransfer(orderNo);
        //确定收货后进行各级代理的分金额
        return orderEntity;

    }


    @Autowired
    private AreaDao areaDao;


    @Autowired
    private SmsService smsService;

}
